<?php
/**
 * Created by PhpStorm.
 * User: wangjie
 * Date: 2020/07/27
 * Time: 下午5:13
 */
namespace App\Api\Controllers\Linkage;


use Illuminate\Support\Facades\Log;

class BaseController
{
    public $postCharset = "UTF-8"; //
    public $fileCharset = "UTF-8"; //

//    public $url = 'http://111.205.18.100:8011/entry-provider-plat-client'; //测试地址
    public $url = 'http://provider.umfintech.com/entry-provider-plat-client'; //生产地址

    public $merchantApply = '/merchants/apply'; //商户入网,主动调用商户信息查询接口来保证商户状态一致性
    public $uploadQualification = '/upload/qualification'; //商户资质上传(图片上传)
    public $merchantsQueryMerchantInfo = '/merchants/queryMerchantInfo'; //商户信息查询(查询商户入网进度信息)
    public $merchantsJsApiPath = '/merchants/jsApiPath'; //微信参数配置-支付授权目录（申请支付授权目录）
    public $merchantsSubAppid = '/merchants/subAppid'; //微信参数配置-子商户appId（申请子商户appId）
    public $signGetVerifyCode = '/sign/getVerifyCode'; //获取电子签约挑战码（通过上传完资质之后，通过该接口获取电子签约挑战码）
    public $signDoVerifyCodeSign = '/sign/doVerifyCodeSign'; //签订电子协议（获取电子协议挑战码之后，通过该接口签订电子协议）
    public $merchantsQueryElectronicAgreement = '/merchants/queryElectronicAgreement'; //下载电子协议
    public $imgmanageSearch = '/imgmanage/search'; //商户资质查询（商户资质文件查询）
    public $merchantsSelectAgentSnNumbers = '/merchants/selectAgentSnNumbers'; //可用终端查询（查询可用终端的厂商、终端型号和SN号）
    public $merchantsAddTerminals = '/merchants/addTerminals'; //商户增加终端（商户入网机具来源为代理商自备的商户，并且审核通过后，调用该接口增加终端）
    public $merchantsQueryBankBrhName = '/merchants/queryBankBrhName'; //查询支行全称（根据支行联行号，查询对应的支行全称）
    public $merchant_bank_info_modify = '/merchants/modifyMerInfo'; //商户信息修改（在审核驳回状态下，商户可以调用此接口对入网的商户信息进行修改；此接口只支持一次调用，调用成功之后即切换至待修改图片状态；如无需修改图片，调用期间需将【结束标识】设置为0，即可直接提交至修改待审核状态）
    public $uploadModifyImgInfo = '/upload/modifyImgInfo'; //资质图片修改（在审核驳回状态（3/5）或修改资质待上传状态（7）下，商户可以调用此接口对上传的资质图片进行修改更新,新修改图片会覆盖原图片；此接口支持多次调用，上传最后一张资质图片时候将【结束标识】设置为0，即可直接提交至修改待审核状态；首次调用此接口，会触发商户状态切换，由驳回待修改状态（3/5）切换至资质待修改状态（7），此状态下无法继续修改商户基本信息）
    public $merchantsModifyAfterSuccess = '/merchants/modifyAfterSuccess'; //入网成功后信息修改（商户入网成功状态下，商户可以调用此接口对入网的商户信息进行修改；此接口支持多次调用，调用成功之后即修改生效；同时修改多条信息，可能出现部分成功部分失败情况，如果存在失败，则返回码为失败返回码，具体失败信息可通过响应中【详细描述】得知；关于微信支付宝费率变更，暂时只支持入网开通产品后调用此接口进行费率修改功能，不支持入网未开通调用此接口开通并报备场景；针对费率信息修改，需要以业务维度同时传入费率字段，详情见【注意事项】1、如果修改 【银行卡费率】(银联扫码业务费率)需要同时传入【银行卡费率一档】与【银行卡费率二档】字段。2、如果修改【银行卡收单费率】(POS业务费率)需要同时传入【银行卡收单费率一档】和【银行卡收单费率二档】字段。3、原D0结算或24小时D0结算，如果修改D0手续费 需要同时传入【附加手续费】和【提现手续费】。4、原D1结算，如果修改D1手续费，需要传入【附加手续费】（附加手续费可为0）。5、如果修改mobilePos相关费率，需要同时传入【手机pos银行卡费率(借记)】，【手机pos银行卡费率(贷记)】，【手机pos银行卡费率(借记封顶)】以及基础的【银行卡收单费率一档】和【银行卡收单费率二档】字段。6、如果无费率修改，则【手续费费率】字段传空的json对象 （格式为：{}）。7、支持由不同结算周期之间的变更修改，如果修改结算周期为D0结算或24小时D0结算，则需要同时传入【附加手续费】和【提现手续费】。如果修改结算周期为D1结算，则需要传入【附加手续费】（附加手续费可为0）。8、结算周期变更后，产品配置即时生效，费率信息修改次日生效，首开即时生效。）

    public $payUnifiedOrder = '/pay/unifiedOrder'; //公众号、小程序支付（通过接口下单成功后，使用返回的预下单信息在微信公众号、微信小程序或支付宝服务窗中调起支付插件，消费者完成支付）
    public $payMicropay = '/pay/micropay'; //刷卡支付-用户被扫（消费者通过微信/支付宝/银联钱包等出示付款码，通过扫码设备识别付款码并完成下单支付）
    public $payQrpay = '/pay/qrpay'; //扫码支付-用户主扫（通过下单接口获取指定支付方式的二维码并展示给消费者，消费者使用微信/支付宝/银联钱包等扫码完成支付）
    public $payQueryOrder = '/pay/queryOrder'; //订单状态同步（平台对服务商的支付请求数据处理完成后，响应为非明确状态。如：“01000000”返回码的情况下，需要调用同步接口，请求通道查询最终结果）
    public $payCancelOrder = '/pay/cancelOrder'; //商户撤销交易（针对交易当天的成功订单可以进行撤销，过了账期则需要走退费接口。仅支持微信支付宝刷卡交易（即用户被扫）的撤销）
    public $payRefund = '/pay/refund'; //商户退款请求（可对支付成功的订单发起退款申请，支持部分退款。退款金额须小于或等于可退款金额，支持对90天以内的成功订单发起退款）
    public $payRefundQuery = '/pay/refundQuery'; //退费状态查询
    public $payCloseOrder = '/pay/closeOrder'; //订单关闭（可对支付失败、支付中的订单发起订单关闭申请。关闭成功的订单不允许继续支付）
    public $payDownloadSettleFile = '/pay/downloadSettleFile'; //get,对账文件下载（商户发送get请求到联动优势下载对应的对账文件）
    public $payWxface = '/pay/wxface'; //刷脸支付-获取调用凭证（针对微信刷脸支付获取SDK调用凭证）
    public $payQuerySettle = '/pay/querySettle'; //查询D0结算结果（平台对服务商的支付请求成功数据。可以调用查询结算结果接口，查询结算结果）
    public $payQueryT1Settle = '/pay/queryT1Settle'; //查询T1/D1结算结果（服务商可以通过该接口，查询商户（T1,D1）对应的结算结果）
    
    public $privateKey = 'MIIEowIBAAKCAQEA2OSacyPWGgZ3PWKLyeRkwpmF5QWK+kD5XEaJ7J4J5nOnJxNfN/iaV/6T3gzI+j7i1Xy+YQSaiJFt+tXovrEPA4xJjqaB89er1CNvFMiIAeJbRhKl90IHeBmPQPkgqFpgKRSiSfQZwtzHlSnSEcH28LVR3tyQ2TJWXXy5/DiA2PMYvRXrJC43KZfk+wvnaFPA1JWIxPHkPNv55tpbFweTFJ2z3yaCB+9X87FZZNHHMeBmE42xSUPCXGWfgt6nzYN6XLGxiDcCtkLRGfU1TQMNg20YZ81tRflCm27v0Q2nG9PuJ6WHvGOBz03gh5Rs9VA49jKGE6YCc41jggUfo95+7QIDAQABAoIBAQDVkSRUQ/FKZxt6olKrVe2xgKJLRQ34JYpkxkCBcYymEzOAUp7r6itwggjwGP69CrcpKE/+EB5qY2k8GO2493elMrorcOF9TdywYsO6X0stL8pYUXyC382jAOgCPk1d+L+/M8Yps+a57dPImQl02t1hX+lh3SXz+JD6NRqdtLWK6ORF1fAKCGwvSZ2StfjWo9YaRJeCZ6hzIdMSnna+NpV3xstSkI27b7tdA/dfUxQ3VJA+F5LlneJIvlMyTYnEGrkFuJNe6Ta6CxTU8B6kW3pW7p6rZe9PQRVQZXN5OWvRdw0M1rMSACjNMoZqYofl/U4VoQdmRoF73V58OW7OY0ABAoGBAPDHM5jX/7p2SnzpB7eEu+JIhIR6jPYyLwKxjMFFqAVJEnN6U1/Dgmm7IX6PIj7+kys2b4fzN8iCqg0+lMTi8TKh95v6Fej6g6jBUEuzHMlEVmpudE0+91z8yB/Iterb4+q+bQnRP1GVg2LINDjObbEc98hRJ030xWkACnr+HBwBAoGBAOaa1ww1VGcvNY2pHTqMysVvejMGsDp/vc8PZ22/3ZBPCrUpakKrg8T+H1UmGHAWUs0kJObH1XQeoSrFxPWF5vrIgoqhzazptZwGTQVSIrKNSGNSjmIxT2kMn1baarmu/KqEtIh74JhUuMiwYG7EPnhZgrsQnzQxOPM3y8nb4JLtAoGAO/7G4ozf0cxr3xgJrjbKwiWjr4cB3M7AXAF1uyrqJPcCO/f9El2a/1F7lReBRwUUEq5ruApomfPE/6vaUfzicOVe12THVNgnOkOBCHvG7neyuK5xGFZaOLdb/l96xNypu/JbJRkYl/GTXWfZa1Y0iu9W5nkiPBCDqBg0hFURGAECgYAoUTX72m8RQz23sLN9gxQIhL72oNq6v46t3uGUXJEeI9OZbM45Lcdx74QG3Qw0vJJpb0JMXu/Ax4Ih+kW/L1P80IWSO0u8SXgI+UkJ/xw132Gii9J89GYP1bcd9j3mjON75IuzuQTBXT6ZR8z0ULcjT3L9xaAv/dMZIs4sUpbm2QKBgBUQXCXqwretouHH2eMFBMysyUL8J8qyOguwWBfBhf28YgMCQbtEOz/2Oxko9WDrexDmAohG3cYJbNmYKBltsjLJXokDhZ3ySrF5sMVc7xvuwyxGfJm2cbsn6xERyWiYuePlLSA8jgPi7x2trgRuyk/DKLSBYXcwfk/aS5X+OrVr';


    /**
     * 执行
     * @param string $url   请求地址后缀
     * @param array $data   请求参数
     * @param string $privateKey    商户私钥
     * @param string $publicKey    联动公钥
     * @return array -1：系统错误 1：成功 2：验签失败
     */
//     public function http_post($url, $data, $privateKey, $publicKey)
//     {
//         //加签
//         $sign = $this->reqSign($data, $privateKey);
//         $data['signature'] = $sign;

//         $data = json_encode($data);

//         $curl = curl_init($url);
//         curl_setopt($curl, CURLOPT_HEADER, false);
//         curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
//         curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/json"));
//         curl_setopt($curl, CURLOPT_POST, true);
//         curl_setopt($curl, CURLOPT_POSTFIELDS, $data);

//         $response = curl_exec($curl);
//         $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

//         if ($response == NULL) {
//             curl_close($curl);
//             return [
//                 'status' => '-1',
//                 'message' => '系统错误'
//             ];
//         } else if ($httpCode != "200") {
//             curl_close($curl);
//             return [
//                 'status' => '-1',
//                 'message' => '系统错误'
//             ];
//         }
// //        Log::info('联动-原始返回');
// //        Log::info($url);
// //        Log::info($response);

//         //返回信息验签
//         $respJsonObj = json_decode($response, true);
// //        Log::info($respJsonObj);

//         $result = $this->respVerifySign($respJsonObj, $publicKey);

//         if ($result) {
//             return [
//                 'status' => '1',
//                 'message' => '成功',
//                 'data' => $respJsonObj
//             ];
//         } else {
//             return [
//                 'status' => '2',
//                 'message' => '验签失败',
//                 'data' => $respJsonObj
//             ];
//         }
// //        return $response;
//     }

    /**
     * 执行
     * @param string $url   请求地址后缀
     * @param array $data   请求参数
     * @param string $privateKey    商户私钥
     * @param string $publicKey    联动公钥
     * @return array -1：系统错误 1：成功 2：验签失败
     */
    public function http_post($isUploadImg, $mehtod, $data){
        if ($isUploadImg) {
            $url = 'https://polymerizationplat.umfintech.com/file/gateway';
        } else {
            $url = 'https://polymerizationplat.umfintech.com/gateway/gateway';
        }
        $data = json_encode($data, JSON_UNESCAPED_UNICODE); // 筛选
        $post_datasign = array(
            "app_id" => "20220923193600349", // 
            "version" => "1.0",
            'method' => $mehtod,
            'content' => $data,
            'track_id' => time(),
        );

        ksort($post_datasign); // 排序
        $joint = '';
        foreach($post_datasign as $k => $v){ // 拼接
            $joint .= $k . '=' . $v . '&';
        }
        $joint = rtrim($joint, '&');
        $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->privateKey, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";

        $key = openssl_get_privatekey($privateKey);
        openssl_sign($joint, $signature, $key);
        openssl_free_key($key);
        $sign = base64_encode($signature); // 签名
        $signdata['sign'] = $sign;
        $post_data = array_merge($post_datasign, $signdata);
        $postdata = http_build_query($post_data);
        

        $curl = curl_init($url);
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-type: application/x-www-form-urlencoded"));
        curl_setopt($curl, CURLOPT_POST, true);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);

        $response = curl_exec($curl);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);
        
        return $response;
    }


    /**
     * 商户秘钥加签
     * @param string $data 之前生成好的需加密内容
     * @param string $key 私钥
     * @return mixed 请求加签
     */
    public function reqSign($data, $key)
    {
        //请求加签
        $sign = $this->rsaSign($data, $key);
        $data['signature'] = $sign;

        return $sign;
    }


    /**
     * RSA签名
     * @param $data 待签名数据
     * @param $private_key 私钥字符串
     * @return string
     */
    private function rsaSign($data, $private_key)
    {
        //001 拼接请求明文串
        $sortData = $this->sortReqFields($data);
//        Log::info('联动-拼接请求明文串');
//        Log::info($data);
//        Log::info($sortData);
        //002 读取请求加签使用私钥
        $res = $this->loadPriKey($private_key);
        if ($res) {
            //003 使用私钥进行加签
            openssl_sign($sortData, $sign, $res, OPENSSL_ALGO_SHA1);
            openssl_free_key($res);
        } else {
            exit("私钥格式有误");
        }

        //004 对签名进行编码
        $sign = base64_encode($sign);

        return $sign;
    }


    /**
     * 拼接需要签名的内容
     * @param array $data 需签名的字段内容
     * @return string
     */
    private function sortReqFields($data)
    {
        unset($data['signature']);
        //递归解json嵌套操作
        foreach ($data as $k => $v) {
            if (is_array($v)) {
                $Parameters[$k] = $this->sortReqFields($v);
            } else {
                $Parameters[$k] = $v;
            }
        }

        //按字典序排序参数
        ksort($Parameters);

        $sign = '';

        foreach ($Parameters as $k => $v) {
            if ($v == null || $v == '') {
                continue;
            }
            //如果值非空则添加
            $sign .= $k . "=" . $v . "&";
        }

        $sign = rtrim($sign, '&');

        return $sign;
    }


    /**
     * 加载请求使用商户私钥
     * @param string $private_key
     * @return bool|resource
     */
    private function loadPriKey($private_key)
    {
        $private_key = chunk_split($private_key, 64, "\n");
        $private_key = "-----BEGIN RSA PRIVATE KEY-----\n" . $private_key . "-----END RSA PRIVATE KEY-----\n";

        $res = openssl_get_privatekey($private_key);

        return $res;
    }


    /**
     * 联动公钥验签
     * @param string $data 要验证的签名
     * @param string $pubCertKey   公钥
     * @return int  验签结果
     */
    public function respVerifySign($data, $pubCertKey)
    {
        $sortData = $this->sortRespFields($data);
//        Log::info('联动-验签');
//        Log::info($sortData);

        $signature = $data['signature'];
        $signature = base64_decode($signature);
        $keys = $this->loadCert($pubCertKey);

        $ok = openssl_verify($sortData, $signature, $keys);

        if($ok == 1){
//            Log::info('联动公钥验签-验签通过');
            return true;
        }else{
            Log::info('联动公钥验签-验签失败');
            return false;
        }

//        return $ok;
    }


    private function sortRespFields($data)
    {
        foreach ($data as $k => $v) {
            if ($k == 'signature') {
                continue;
            }
            if (is_array($v)) {
                $Parameters[$k] = $this->sortRespFields($v);
            } else {
                $Parameters[$k] = $v;
            }
        }

        //按字典序排序参数
        ksort($Parameters);

        $sign = '';

        foreach ($Parameters as $k => $v) {
            if ($v == null || $v == '') {
                continue;
            }
//            $domain = strstr($v, '"');
//            if($domain != false){
//                $v = str_replace('"',"",$v);
//            }

            $sign .= $v . "|";
        }

        $sign = rtrim($sign, '|');

        return $sign;
    }


    /**
     * 获取响应验签使用联动公钥
     * @param string $pubCertKey 公钥
     * @return mixed
     */
    private function loadCert($pubCertKey)
    {
        $cert = chunk_split($pubCertKey, 64, "\n");
        $cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n";

        $res = openssl_pkey_get_public($cert);
        $detail = openssl_pkey_get_details($res);
        openssl_free_key($res);

        if (!$detail) {
            throw new Exception('loadX509Cert::openssl_pkey_get_details ERROR');
        }

        return $detail['key'];
    }


}
